在上一篇文章中,我們逐步建立了 Hero Section,並結合 i18n 和 Framer Motion,來增強其動態效果與語言支持。
今天,我們將繼續加強 Hero Section,著重於如何透過數據展示動畫與滾動觸發效果,來進一步提升使用者的互動體驗。具體來說,我們將使用 react-countup 和 react-intersection-observer 來實現滾動觸發的數據動畫效果,並介紹兩種動態變更 SVG 顏色的方法。同時,我們還會實現 Tooltip 提示功能,讓用戶在懸停圖片或數據時能獲取更多信息。
接下來,請參照下圖中的紅色標註部分,我們今天的主要目標是:
react-countup
來實現數據的動態增長效果,並透過 react-intersection-observer
,在使用者滾動到特定區域時觸發動畫。mask
技術,根據具體需求選擇最合適的方案。在設計過程中,我們採用了兩種方式來實現 SVG 顏色的動態變更。不同的方法適合不同場景,以下是兩者的比較:
方法 | 優點 | 缺點 | 使用情境 |
---|---|---|---|
內嵌 SVG 並傳遞參數 | - 精細控制 SVG 的屬性(如 strokeColor 、strokeWidth ) |
較大的代碼量,複雜 SVG 可能影響頁面性能 | 適用於需要頻繁變更顏色和精細控制的情境,如圖標 |
CSS mask |
-簡單、快速改變顏色 | 僅適用於簡單圖案,無法處理複雜 SVG | 適合簡單的裝飾性圖形,如分隔線等 |
在本文的實作中,我們運用了這兩種技術:在需要靈活調整圖標顏色和樣式的情境下,使用了內嵌 SVG 並通過參數控制;而在簡單的裝飾性元素中則使用了 CSS mask
技術來進行色彩變更。
react-countup
和 react-intersection-observer
我們將使用 react-countup 來實現數據的動態展示,並使用 react-intersection-observer 來偵測用戶滾動到數據展示區域的狀態。打開終端通過 npm 安裝這兩個庫:
npm install react-countup
npm install react-intersection-observer
StatsSection
元件接下來,我們創建一個 StatsSection
元件,用來展示統計數據。這個元件使用 CountUp 來展示數據增長效果,並通過 useInView 來監聽滾動事件,當使用者滾動到指定區域時觸發動畫效果。
import React from 'react'
import CountUp from "react-countup";
import * as styles from '@/components/Cards/StatsSection.module.scss'
import Separator from '@/assets/portfolio/separator.svg'; // 引入 SVG 文件
import { useInView } from 'react-intersection-observer';
const StatsSection = () => {
const stats = [
{ num: 12, text: 'Years of Experience' },
{ num: 200, text: 'Projects Completed' },
{ num: 8, text: 'Technology Mastered' }
];
const { ref, inView } = useInView({
triggerOnce: true,
threshold: 0.5, // 當用戶滾動到元素一半時觸發
});
return (
<div className={styles.statsContainer} ref={ref}>
{
stats.map((item, index) => {
return <div className={styles.stats} key={index}>
<div className={styles.statsItem}>
<CountUp end={item.num}
duration={5}
delay={2}
className={styles.number} />
<p className={styles.label}>{item.text}</p>
</div>
{index < stats.length - 1 && (
<div className={styles.separator} />
)}
</div>
})
}
</div>
)
}
export default StatsSection
SVG
顏色我們在StatsSection.module.scss
運用 CSS mask
技術來動態更改 SVG 顏色。這裡將 SVG 分隔線設置為一個背景遮罩,並通過 background-color
動態調整其顏色。
.separator {
mask: url('@/assets/portfolio/separator.svg') no-repeat center;
background-color: var(--text-primary); // 用來改變 SVG 顏色
width: 100px; // 根據需要調整
height: 100px; // 根據需要調整
margin: 0 20px;
}
ComputerIcon
元件我們將使用一個內嵌的 SVG 元件 ComputerIcon
,允許通過傳遞參數來動態調整顏色和線條寬度,這樣更適合需要精細控制的場景。
import React from 'react'
const ComputerIcon = ({ strokeColor = 'black', fillColor = 'none', strokeWidth = 0.5 }) => {
return (
<svg width="192" height="155" viewBox="0 0 192 155" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* 其他 SVG 路徑 */}
<line y1="-0.25" x2="48.7919" y2="-0.25" transform="matrix(0.766664 -0.642049 0.583457 0.812144 73.3784 124.914)" stroke={strokeColor} strokeWidth={strokeWidth} />
</svg>
)
}
export default ComputerIcon
為了提供額外的數據說明,我們會設置一個 Tooltip 組件,當用戶懸停在圖片上時顯示額外的信息。這裡我們使用了 Framer Motion
來實現動畫效果。
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import * as styles from '@/components/Tooltip/Tooltip.module.scss'
const Tooltip = ({ children, text }) => {
const [isVisible, setIsVisible] = useState(false);
const showTooltip = () => setIsVisible(true);
const hideTooltip = () => setIsVisible(false);
return (
<div className={styles.tooltipContainer} onMouseEnter={showTooltip} onMouseLeave={hideTooltip}>
{children}
{isVisible && (
<motion.div
className={styles.tooltipBox}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
>
{text}
<div className={styles.tooltipArrow} />
</motion.div>
)}
</div>
);
};
export default Tooltip;
Portfolio
件元件接下來,我們將把 StatsSection
、ComputerIcon
和 Tooltip
元件整合進 Portfolio
頁面,並展示統計數據和圖標。當用戶懸停在圖片時,會顯示 Tooltip。
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { log, logLevel } from '@/utils/log';
import Button from '@/components/buttons/Button';
import * as styles from '@/pages/Portfolio/Portfolio.module.scss'; // 使用模塊化的樣式
import { motion } from 'framer-motion'; // 引入 Framer Motion
import StatsSection from '@/components/Cards/StatsSection';
import ComputerIcon from '@/components/Icons/ComputerIcon';
import Tooltip from '@/components/Tooltip/Tooltip';
const Portfolio = () => {
const { t, i18n } = useTranslation();
log(logLevel.DEBUG, 'Portfolio rendered');
// 定義一個簡單的淡入動畫
const fadeIn = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: { duration: 1.5 } },
};
return (
<>
<div className={`${styles.heroContainer} ${i18n.language}`} data-lang={i18n.language}>
<div className={styles.heroContent}>
<ComputerIcon strokeColor="var(--text-primary)" fillColor="var(--text-primary)" strokeWidth={0.5} />
<motion.h1
className={styles.heroTitle}
initial="hidden"
animate="visible"
variants={fadeIn}
>
<Trans i18nKey="portfolio.title">
I craft <span className={styles.highlight}>beautiful</span> websites 💻 with love.
</Trans>
</motion.h1>
<Button
type="primary"
afterContent={require('@/assets/buttons/dot.svg')}
size="large"
>
{t('portfolio.contact')}
</Button>
</div >
<div className={styles.imageContainer}>
<Tooltip text="Meet Carol </>">
<img className={styles.heroImage} src={require('@/assets/portfolio/heroimage.png')} alt="Meet Carol" />
</Tooltip>
</div>
</div>
<StatsSection />
</>
)
}
export default Portfolio
在這段代碼中,我們將 Tooltip
元件應用於按鈕和圖片上,當用戶懸停時會顯示提示訊息,增加互動性。
運行後,數據區域在滾動時觸發動畫,SVG 圖標顏色隨參數變化,並且在懸停圖片時顯示 Tooltip,增強了互動性和視覺效果。
在今天的文章中,我們展示了如何在 Hero Section 中增強互動體驗,通過 react-countup
和 react-intersection-observer
實現滾動觸發的數據動畫效果,並介紹了兩種 SVG 顏色變更的方法。最後,我們還實作了 Tooltip 元件,進一步提升頁面的可用性和互動性。
此外,我們已將完整的代碼實作與更多練習題上傳至 GitHub,鼓勵大家前往查看,並回顧文章中的概念,挑戰更進階的優化練習。
👉 前往 GitHub 查看完整程式碼